package com.mindata.blockchain.block.RLP;

import com.mindata.blockchain.block.Instruction;
import com.mindata.blockchain.common.util.ByteUtil;
import com.mindata.blockchain.common.util.RLP;
import com.mindata.blockchain.common.util.RLPList;

/**
 * Created by Ming on 2018/8/10.
 */
public class InstructionB extends InstructionBaseB {

    private byte[] json;

    private byte[] timeStamp;

    private byte[] publiceKey;

    private byte[] sign;

    private byte[] hash;

    protected byte[] rlpEncoded;

    private boolean parsed = false;

    public InstructionB() {
    }

    public InstructionB(Instruction instruction) {
        setJson(instruction.getJson() != null ? instruction.getJson().getBytes() : EMPTY_BYTE_ARRAY);
        setTimeStamp( instruction.getTimeStamp() != null ? ByteUtil.longToBytes(instruction.getTimeStamp()) : EMPTY_BYTE_ARRAY);
        setPubliceKey( instruction.getPublicKey() != null ? instruction.getPublicKey().getBytes() : EMPTY_BYTE_ARRAY);
        setSign(instruction.getSign() != null ? instruction.getSign().getBytes() : EMPTY_BYTE_ARRAY);
        setHash(instruction.getHash() != null ? instruction.getHash().getBytes() : EMPTY_BYTE_ARRAY);

        setOperation(instruction.getOperation());
        setTable(instruction.getTable() != null ? instruction.getTable().getBytes() : EMPTY_BYTE_ARRAY);
        setOldJson(instruction.getOldJson() != null ? instruction.getOldJson().getBytes() : EMPTY_BYTE_ARRAY);
        setInstructionId(instruction.getInstructionId() != null ? instruction.getInstructionId().getBytes() : EMPTY_BYTE_ARRAY);
        this.rlpEncoded = null;
    }

    public InstructionB(byte[] rawData) {
        this.rlpEncoded = rawData;
        RLPList params =(RLPList)(RLP.decode2(rlpEncoded)).get(0);
        RLPList instructionBase = (RLPList) params.get(5);
        super.rlpEncoded = instructionBase.getRLPData();
    }

    public byte[] getJson() {
        parseRLP();
        return json;
    }

    private synchronized void parseRLP() {
        if (parsed)
            return;
        RLPList params = (RLPList) RLP.decode2(rlpEncoded).get(0);

        this.json = params.get(0).getRLPData();
        this.timeStamp = params.get(1).getRLPData();
        this.publiceKey = params.get(2).getRLPData();
        this.sign = params.get(3).getRLPData();
        this.hash = params.get(4).getRLPData();

        this.parsed = true;
    }

    public void setJson(byte[] json) {
        this.json = json;
    }

    public byte[] getTimeStamp() {
        parseRLP();
        return timeStamp;
    }

    public void setTimeStamp(byte[] timeStamp) {
        this.timeStamp = timeStamp;
    }

    public byte[] getPubliceKey() {
        parseRLP();
        return publiceKey;
    }

    public void setPubliceKey(byte[] publiceKey) {
        this.publiceKey = publiceKey;
    }

    public byte[] getSign() {
        parseRLP();
        return sign;
    }

    public void setSign(byte[] sign) {
        this.sign = sign;
    }

    public byte[] getHash() {
        parseRLP();
        return hash;
    }

    public void setHash(byte[] hash) {
        this.hash = hash;
    }

    public byte[] encode() {
        if (rlpEncoded == null) {
            byte[] json = encode(this.json);
            byte[] timeStamp = encode(this.timeStamp);
            byte[] publiceKey = encode(this.publiceKey);
            byte[] sign = encode(this.sign);
            byte[] hash = encode(this.hash);
            rlpEncoded = RLP.encodeList(json, timeStamp, publiceKey, sign, hash, super.encode());
        }
        return rlpEncoded;
    }

    public byte[] encode(byte[] var) {
        return RLP.encodeElement(var);
    }

    public Instruction convertToInstruction() {
        parseRLP();

        Instruction instruction = new Instruction();

        if (!ByteUtil.isNullOrZeroArray(getJson()))
            instruction.setJson(new String(getJson()));

        if (!ByteUtil.isNullOrZeroArray(getTimeStamp()))
            instruction.setTimeStamp(ByteUtil.byteArrayToLong(getTimeStamp()));

        if (!ByteUtil.isNullOrZeroArray(getPubliceKey()))
            instruction.setPublicKey(new String(getPubliceKey()));

        if (!ByteUtil.isNullOrZeroArray(getSign()))
            instruction.setSign(new String(getSign()));

        if (!ByteUtil.isNullOrZeroArray(getHash()))
            instruction.setHash(new String(getHash()));

        if (!ByteUtil.isNullOrZeroArray(getInstructionId()))
            instruction.setInstructionId(new String(getInstructionId()));

        instruction.setOperation(getOperation());

        if (!ByteUtil.isNullOrZeroArray(getTable()))
            instruction.setTable(new String(getTable()));

        if (!ByteUtil.isNullOrZeroArray(getOldJson()))
            instruction.setOldJson(new String(getOldJson()));

        if (!ByteUtil.isNullOrZeroArray(getInstructionId()))
            instruction.setInstructionId(new String(getInstructionId()));

        return instruction;
    }
}
